package org.linlinjava.litemall.db.service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.db.dao.WxUserMapper;
import org.linlinjava.litemall.db.domain.WxUser;
import org.linlinjava.litemall.db.domain.WxUserExample;
import org.linlinjava.litemall.db.util.TaskExcutor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.github.pagehelper.PageHelper;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;

@Service
public class WxUserService {
	
	private final Log logger = LogFactory.getLog(WxUserService.class);
	
	@Autowired
	private WxUserMapper wxUserMapper;
	@Autowired
	private WxMpService wxService;
	
    private volatile static  boolean syncWxUserTaskRunning = false;
	
	public List<WxUser> querySelective(String username,Integer page,Integer limit){
		WxUserExample example = new WxUserExample();
		WxUserExample.Criteria criteria = example.createCriteria();
		
		if(!StringUtils.isEmpty(username)) {
			criteria.andNicknameLike("%" + username + "%");
		}
		PageHelper.startPage(page, limit);
		return wxUserMapper.selectByExample(example);
	}
	
	public List<WxUser> selectByExample(String username, Integer page, Integer limit){
		WxUserExample example = new WxUserExample();
		WxUserExample.Criteria criteria = example.createCriteria();
		
		if(!StringUtils.isEmpty(username)) {
			criteria.andNicknameLike("%" + username + "%");
		}
		PageHelper.startPage(page, limit);
		return wxUserMapper.selectByExample(example);
	}
	
	public void add(WxUser user) {
		user.setSubscribeTime(LocalDateTime.now());
		wxUserMapper.insertSelective(user);
	}
	
	public void add(WxMpUser mpUser) {
		WxUser wu = new WxUser();
		BeanUtils.copyProperties(mpUser, wu);
		wu.setSubscribeTime(LocalDateTime.now());
		wxUserMapper.insertSelective(wu);
		/*
		//先查询是否已存在
		WxUser wxUser = wxUserMapper.selectByPrimaryKey(mpUser.getOpenId());
		if(wxUser == null) {
			WxUser wu = new WxUser();
			BeanUtils.copyProperties(mpUser, wu);
			wu.setSubscribeTime(LocalDateTime.now());
			wxUserMapper.insertSelective(wu);
		}else {
			WxUser wu = new WxUser();
			wu.setSubscribe(true);
			wxUserMapper.updateByPrimaryKeySelective(wu);
		}
		//Byte subscribe = 1;
		//wu.setSubscribe(subscribe);
		/*
		wu.setOpenid(mpUser.getOpenId());
		//wu.setPhone();
		wu.setNickname(mpUser.getNickname());
		wu.setSex(mpUser.getSex());
		wu.setSex(sex);
		wu.setCity(city);
		wu.setProvince(province);
		wu.setHeadimgurl(headimgurl);
		wu.setSubscribeTime(subscribeTime);
		wu.setSubscribe(subscribe);
		wu.setUnionid(unionid);
		wu.setRemark(remark);
		wu.setSubscribeScene(subscribeScene);
		wu.setQrSceneStr(qrSceneStr);
		wu.setTagidList(tagidList);*/
	}
	
	public WxUser getOneUser(String openId) {
		return wxUserMapper.selectByPrimaryKey(openId);
	}
	
	public WxUser getUserByUnionId(String UnionId) {
		return wxUserMapper.getUserByUnionId(UnionId);
	}
	
	public void update(WxUser user) {
		wxUserMapper.updateByPrimaryKey(user);
	}
	
	public void unsubscribe(String openId) {
		WxUser wu = new WxUser();
		wu.setOpenId(openId);
		wu.setSubscribe(false);
		wxUserMapper.updateByopenId(wu);
	}
	
	@Async
	public void syncWxUsers() {
    	if(syncWxUserTaskRunning) {
            return;//同步较慢，防止个多线程重复执行同步任务
        }
    	syncWxUserTaskRunning = true;
		boolean hasMore=true;
		String nextOpenid=null;
		//获取数据库全部数据
		List<WxUser> wxUserList = wxUserMapper.selectAll();
		for(WxUser w : wxUserList) {
			excludeOpenIds.add(w.getOpenId());
		}
		WxMpUserService wxMpUserService = wxService.getUserService();
		try {
			while (hasMore){
				WxMpUserList wxMpUserList = wxMpUserService.userList(nextOpenid);//拉取openid列表，每次最多1万个
				//logger.info("拉取openid列表：第{}页，数量：{}",page++,wxMpUserList.getCount());
				List<String> openids = wxMpUserList.getOpenids();
				this.saveWxUsers(openids,wxUserList);
				nextOpenid=wxMpUserList.getNextOpenid();
				hasMore=!StringUtils.isEmpty(nextOpenid) && wxMpUserList.getCount()>=10000;
			}
		} catch (WxErrorException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			logger.error("同步公众号粉丝出错:",e);
		}
		//完成
		syncWxUserTaskRunning=false;
		//updateUserSubscribe();
	}
	
	public void saveWxUsers(List<String> openids,List<WxUser> dataList) {
		if(openids.size()<1) {
            return;
        }
		final String batch=openids.get(0).substring(20);//截取首个openid的一部分做批次号（打印日志时使用，无实际意义）
		WxMpUserService wxMpUserService = wxService.getUserService();
		int start=0,batchSize=openids.size(),end=Math.min(100,batchSize);
		//logger.info("开始处理批次：{}，批次数量：{}",batch,batchSize);
		while (start<end && end<=batchSize){//分批处理,每次最多拉取100个用户信息
			final int finalStart = start,finalEnd = end;
			final List<String> subOpenids=openids.subList(finalStart,finalEnd);
			//TaskExcutor.submit(()->{//使用线程池同步数据，否则大量粉丝数据需同步时会很慢
				//logger.info("同步批次:【{}--{}-{}】，数量：{}",batch, finalStart, finalEnd,subOpenids.size());
				//wxService.switchover(appid);
				List<WxMpUser> wxMpUsers = null;//批量获取用户信息，每次最多100个
				try {
					wxMpUsers = wxMpUserService.userInfoList(subOpenids);
				} catch (WxErrorException e) {
					//logger.error("同步出错，批次：【{}--{}-{}】，错误信息：{}",batch, finalStart, finalEnd,e);
				}
				if(wxMpUsers!=null && !wxMpUsers.isEmpty()){
					//List<WxUser> wxUsers=wxMpUsers.parallelStream().map(item->new WxUser(item,appid)).collect(Collectors.toList());
					//this.saveOrUpdateBatch(wxUsers);
					List<WxUser> newWxUser = getNewWxMpUser(wxMpUsers,subOpenids);
					if(newWxUser.size()>0) {
						//新增
						wxUserMapper.batchInsert(newWxUser);
					}
					/*
					List<WxUser> oldWxUser = getOldWxMpUser(wxMpUsers,subOpenids);
					if(oldWxUser.size()>0) {
						//修改
						wxUserMapper.batchUpdate(oldWxUser);
					}*/
					//wxUserMapper.batchUpdateUnsubscribe(excludeOpenIds);
					//更新用户表
					//System.out.println("更新用户表");
				}
			//});
			start=end;
			end=Math.min(end+100,openids.size());
		}
		//wxUserMapper.batchUpdateUnsubscribe(excludeOpenIds);
		//excludeOpenIds.clear();
		//subscribe.clear();
		//updateUserSubscribe();
		//logger.info("批次：{}处理完成",batch);
	}
	/*
	private void updateUserSubscribe() {
		if(excludeOpenIds.size()>0) {
			TaskExcutor.submit(()->{
				System.out.println("取消关注用户："+excludeOpenIds.size());
				wxUserMapper.batchUpdateUnsubscribe(excludeOpenIds);
			});
		}
		System.out.println("取消关注用户："+excludeOpenIds.size());
		excludeOpenIds.clear();
		subscribe.clear();
	}*/
	
	List<String> excludeOpenIds = new ArrayList<>();
	List<String> subscribe = new ArrayList<>();
	
	
	/**
	 * 获取新的关注用户
	 * 
	 * @param wxMpUserinfo	微信接口数据
	 * @param dataList	数据库数据
	 * @return
	 */
	private List<WxUser> getNewWxMpUser(List<WxMpUser> wxMpUserinfoList,List<String> subOpenids){
		List<WxUser> newWxUser = new ArrayList<>();
		List<WxUser> oldWxUser = new ArrayList<>();

		for(WxMpUser wxMpUser : wxMpUserinfoList) {
			if(!excludeOpenIds.contains(wxMpUser.getOpenId())) {
				subscribe.add(wxMpUser.getOpenId());//关注用户的openid
				WxUser u = new WxUser();
				BeanUtils.copyProperties(wxMpUser, u);
				u.setSubscribeTime(LocalDateTime.ofEpochSecond(wxMpUser.getSubscribeTime(), 0, ZoneOffset.ofHours(8)));
				newWxUser.add(u);
			} else if(wxMpUser.getSubscribe()) {
				//重复关注用户
				subscribe.add(wxMpUser.getOpenId());
				WxUser u = new WxUser();
				BeanUtils.copyProperties(wxMpUser, u);
				u.setSubscribeTime(LocalDateTime.ofEpochSecond(wxMpUser.getSubscribeTime(), 0, ZoneOffset.ofHours(8)));
				oldWxUser.add(u);
			}
		}
		//修改重复关注用户状态
		if(oldWxUser.size()>0) {
			//修改
			wxUserMapper.batchUpdate(oldWxUser);
		}
		//修改取关用户状态
		
		excludeOpenIds.removeAll(subscribe);
		if(excludeOpenIds.size()>0) {
			wxUserMapper.batchUpdateUnsubscribe(excludeOpenIds);
		}
		return newWxUser;
	}
	
	/*
	private List<WxUser> getOldWxMpUser(List<WxMpUser> wxMpUserinfoList,List<String> subOpenids){
		List<WxUser> oldWxUser = new ArrayList<>();
		for(WxMpUser wxMpUser : wxMpUserinfoList) {
			if(excludeOpenIds.contains(wxMpUser.getOpenId())) {
				//excludeOpenIds.add(wxMpUser.getOpenId());
				
				WxUser u = new WxUser();
				BeanUtils.copyProperties(wxMpUser, u);
				u.setSubscribeTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(wxMpUser.getSubscribeTime()), ZoneId.systemDefault()));
				
				oldWxUser.add(u);
			}
		}
		//排除存在的openid列表
		subOpenids.removeAll(excludeOpenIds);
		//排除存在的粉丝
		//wxMpUserinfoList.removeAll(oldWxUser);
		return oldWxUser;
	}*/
}
